﻿package we3d.animation 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.getTimer;
	import we3d.Scene3d;
	
	/**
	* A ScenePlayer updates the frame property of a scene.
	*/
	public class ScenePlayer extends EventDispatcher 
	{
		/**
		* Creates a new ScenePlayer
		* @param	_scene the scene to play
		* @param	_stage sprite used for enterFrame handler, the sprite have to be on the stage
		*/
		public function ScenePlayer (_scene:Scene3d, _stage:Sprite)	{
			scene = _scene;
			stage = _stage;
		}
		/**
		* The stage is used to listen to ENTER_FRAME events
		*/
		public var stage:Sprite;
		/**
		* Event when the ScenePlayer loops to the first frame
		*/
		public static var EVT_LOOPSCENE:String = "evt_loopscene";
		/**
		* Event when the ScenePlayer stops the scene
		*/
		public static var EVT_STOPSCENE:String = "evt_stopscene";
		/** 
		* Loop the Scene after the last frame or stop at the last frame 
		*/
		public var loopScene:Boolean = true;	
		/**
		* If true, the current frame is the current time in milliseconds
		*/
		public var timeBased:Boolean = false;
		/**
		* The first frame of the timeline
		*/
		public var firstFrame:Number = 1;
		/**
		* The last frame of the timeline
		*/
		public var lastFrame:Number = 100;
		/**
		* The frame step of the timeline
		*/
		public var frameStep:Number = 1;
		
		private var dir:Number = 1;
		private var _currentFrame:Number = 1;
		private var scene:Scene3d;
		private var timeStart:Number = 0;
		private var _isPlaying:Boolean = false;
		
		/**  
		* Read Only, true if the scene is playing  
		*/
		public function get isPlaying () :Boolean {
			return _isPlaying;
		}
		
		/**
		* @return the current frame or the current time if <code>timeBased</code> is true
		*/
		public function get currentFrame () :Number {
			if(timeBased) {
				return dir < 0 ? timeStart - getTimer() : getTimer() - timeStart;
			}else{
				return _currentFrame;
			}
		}
		
		/**	
		* Set the current frame
		* @param frame the current frame, first frame is 1
		*/
		public function set currentFrame (frame:Number) :void {	
			if(timeBased) {
				timeStart = getTimer() + (dir < 0 ? frame : -frame);
			}else{
				_currentFrame = frame;
			}
		}
		
		public function frameHandler (e:Event) :void {
			var cf:Number = _currentFrame;
			
			if((dir > 0 && cf >= lastFrame) || (dir <= 0 && cf <= lastFrame)) {
				if(loopScene == false) {
					stopScene();
					dispatchEvent(new Event(EVT_STOPSCENE));
				}else{
					drawFrame();
					currentFrame = firstFrame;
					dispatchEvent(new Event(EVT_LOOPSCENE));
				}
				return;
			}
			
			drawFrame();
			
			if(!timeBased) 
				currentFrame = cf+dir;
		}
		
		/**	
		* Play the Scene
		* @param ff first frame
		* @param lf last frame
		* @param fs frame step if timeBased is false, if timeBased is true fs should be set to the fps of the swf movie
		* @param loop if false, the scene stop at the last frame
		* @param updateEveryFrame if false you have to call we.setRenderState() if properties changes.
		*/
		public function playScene (ff:Number=-1, lf:Number=-1, fs:Number=-1, loop:*=null) :void {
			if(ff != -1) firstFrame = ff;
			if(lf != -1) lastFrame = lf;
			if(fs != -1) frameStep = fs;
			if(loop != null) loopScene = Boolean(loop);
			if(frameStep <= 0) frameStep = 1;
			
			if(timeBased) {
				dir = (firstFrame > lastFrame ?  -1 : 1) * 1000/frameStep;
			}else{
				dir = (firstFrame > lastFrame ?  -1 : 1) * frameStep;
			}
			
			if(!_isPlaying) {
				currentFrame = firstFrame;
				frameHandler(null);
				_isPlaying = true;
				stage.addEventListener(Event.ENTER_FRAME, frameHandler);
			}
		}
		
		/**	
		* Stop playing 
		*/
		public function stopScene () :void {
			if(_isPlaying) {
				_isPlaying = false;
				stage.removeEventListener(Event.ENTER_FRAME, frameHandler);
			}
		}
		
		/**
		* @private
		*/
		private function drawFrame () :void {
			scene.currentFrame = currentFrame;
		}
		
	}
}
